package main

import (
	"fmt"
	"reflect"
	"unicode/utf8"
	"unsafe"
)

// 值
func function01() {
	fmt.Println(123_456)       // 123456
	fmt.Println("go" + "lang") // golang

	fmt.Println("1 + 1 = ", 1+1)     // 1 + 1 =  2
	fmt.Println("3 / 2 = ", 3/2)     // 3 / 2 =  1
	fmt.Println("7.0 / 3 = ", 7.0/3) // 7.0 / 3 =  2.3333333333333335

	fmt.Println(true && false) // false
	fmt.Println(true || false) // true
	fmt.Println(!true)         // false
}

// 指针类型
func function02() {
	a := 1
	ptr := func(b *int) {
		fmt.Println(&b, b) // 0xc000088028 0xc00000a0c8
		*b = 2
		fmt.Println(*b) // 2
	}
	fmt.Println(&a) // 0xc00000a0c8
	ptr(&a)
	fmt.Println(a) // 2
}

// 引用类型
func function03() {
	s := []int{1, 2}
	ref := func(a []int) {
		fmt.Printf("%p\n", &a) // 0xc000008060
		a[1] = 0
		fmt.Println(a) // [1 0]
	}
	fmt.Printf("%p\n", &s) // 0xc000008048
	ref(s)
	fmt.Println(s) // [1 0]
}

// 传"引用"
func function04() {
	a := make([]int, 1, 2) // 指定len(a)=1,cap(a)=2
	a[0] = 1
	fmt.Println(len(a), cap(a), a) // 1 2 [1]
	ref := func(b []int) {
		b[0] = 4
		fmt.Println(len(b), cap(b), b, len(a), cap(a), a) // 1 2 [4] 1 2 [4]
		b = append(b, 2)
		fmt.Println(len(b), cap(b), b, len(a), cap(a), a) // 2 2 [4 2] 1 2 [4]
		b[0] = 0
		fmt.Println(len(b), cap(b), b, len(a), cap(a), a) // 2 2 [0 2] 1 2 [0]

		b = append(b, 3)
		fmt.Println(len(b), cap(b), b, len(a), cap(a), a) // 3 4 [0 2 3] 1 2 [0]
		b[0] = 1
		fmt.Println(len(b), cap(b), b, len(a), cap(a), a) // 3 4 [1 2 3] 1 2 [0]
	}
	ref(a)
}

// 变量
func function05() {
	var a int64          // 声明未初始化，默认 int64(0)
	var b string = "ABC" // 标准声明并初始化
	var c = 1            // 自动类型推导
	var d, e = 2, "3"    // 一次初始化多个变量

	// 批量声明
	var (
		f float64 = 3.1
		g bool    = false
	)

	h := .1 // 简短变量声明

	fmt.Println(a, b, c, d, e, f, g, h) // 0 ABC 1 2 3 3.1 false 0.1
}

// 常量
func function06() {
	const pi = 3.1415
	// 同时声明多个常量，某个常量省略值，则和上一个相同
	const (
		e = 2.7182
		a // 2.7182
		b // 2.7182
		c = 3
		d // 3
	)
	// iota 预声明标识符，表示连续的无类型整数常量，初始值 0
	const (
		level1 = iota + 1 // 1
		level2            // 2
		level3            // 3
		_                 // 跳过某些值
		level5            // 5
		n      = 1000     // 在 iota 声明中插队
		level6 = iota     // 6, 需要再使用 iota
	)

	// 多个 iota 定义在一行，iota 值逐行增加
	const (
		A, B = iota + 1, iota + 2 // 1 2
		C, D                      // 2 3
		E, F                      // 3 4
	)

	// 用来定义数量级
	const (
		_  = iota
		KB = 1 << (10 * iota) // 1 << (10 * 1)
		MB = 1 << (10 * iota) // 1 << (10 * 2)
		GM = 1 << (10 * iota) // 1 << (10 * 3)
		TB = 1 << (10 * iota) // 1 << (10 * 4)
	)
}

// 字符串
func function07() {
	s1 := "123"
	s2 := "字符串"
	s3 := `第一行
第二行
第三行
`
	// s1[0] = '4' 						   // 不能修改
	s1 += "456"                            // 123456
	fmt.Println(len(s1), len(s2), len(s3)) // 3 9 30
}

// byte、rune
func function08() {
	var a = 'a'
	var b byte = 'b'
	fmt.Println(unsafe.Sizeof(a), unsafe.Sizeof(b)) // 4 1

	s1 := "Golang语言"
	fmt.Println(len(s1), utf8.RuneCountInString(s1)) // 12 8

	for i := 0; i < len(s1); i++ {
		fmt.Printf("%c", s1[i])
	} // Golangè¯­è¨
	fmt.Println()
	for _, s := range s1 {
		fmt.Printf("%c", s)
	} // Golang语言
}

func function09() {
	// 仅声明字符串
	var str string
	var stringHeader = (*reflect.StringHeader)(unsafe.Pointer(&str))
	fmt.Printf("%p %p %d\n", &str, unsafe.Pointer(stringHeader.Data), stringHeader.Len)

	// 字符串赋值
	str = "快速入门"
	fmt.Printf("%p %p %d\n", &str, unsafe.Pointer(stringHeader.Data), stringHeader.Len)

	// 字符串拼接
	str += "GO语言"
	fmt.Printf("%p %p %d\n", &str, unsafe.Pointer(stringHeader.Data), stringHeader.Len)

	// 字符串转 byte 切片
	var bytes = []byte(str)
	fmt.Printf("%p %p %d\n", bytes, unsafe.Pointer(stringHeader.Data), stringHeader.Len)
	bytes[3] = 1
	fmt.Println(str)

	// 0拷贝 byte 切片转换
	var bytes1 = *(*[]byte)(unsafe.Pointer(&str))
	fmt.Printf("%p %p %d\n", bytes1, unsafe.Pointer(stringHeader.Data), stringHeader.Len)
	bytes1[3] = 1
	fmt.Println(str)
}

// 运算符
func function10() {
	var a int
	a++
	fmt.Println(a) // 1
	// b := a--  错误！i++、i--只能单独使用
	// ++a 错误！没有 ++i、--i 操作

	x := 11
	y := (1 << 0) | (1 << 3) // 保证 z 中的第 0 位和第 3 位为 0
	z := x &^ y
	fmt.Printf("x = %b\n", x)
	fmt.Println("\t&^")
	fmt.Printf("y = %b\n", y)
	fmt.Println("————————")
	fmt.Printf("z = %04b\n", z)
	/*
		x = 1011
				&^
		y = 1001
		————————
		z = 0010
	*/
}

// for
func function11() {
	i := 1
	for i < 2 {
		fmt.Println(i)
		i++
	} // 1

	for j := 8; j < 9; j++ {
		fmt.Println(j)
	} // 8

	for {
		fmt.Println("loop")
		break
	} // loop

	for n := 1; n <= 3; n++ {
		if n%2 == 0 {
			continue
		}
		fmt.Println(n)
	} // 1 3

	var num int
flag:
	num++
	for num <= 3 {
		fmt.Println(num)
		goto flag
	} // 1 2 3

	s := []int{11, 12}
	for k, v := range s {
		fmt.Println(k, v)
	} // 0 11; 1 12
}

// if-else
func function12() {
	score := 70
	if score < 60 {
		fmt.Println("不及格")
	} else if score >= 60 && score <= 80 {
		fmt.Println("良好")
	} else {
		fmt.Println("优秀")
	} // 良好

	if err := 1; err != 0 {
		fmt.Println("没有出错")
	} // 没有出错
}

// switch case
func function13() {
	switch suf := ".a"; suf {
	case ".html":
		fmt.Println("页面")
	case ".doc", ".txt":
		fmt.Println("文档")
	case ".js":
		fmt.Println("脚本文件")
	default:
		fmt.Println("其它后缀")
	} // 其它后缀
}

// fallthrough
func function14() {
	var suf = ".doc"
	switch suf {
	case ".html":
		fmt.Println("页面")
	case ".doc":
		fmt.Println("文档")
		fallthrough
	case ".js":
		fmt.Println("脚本文件")
	default:
		fmt.Println("其它后缀")
	} // 文档 脚本文件
}

// 指针
func function15() {
	str := "123"
	var strPtr *string = &str
	fmt.Println(str, *strPtr)          // 123 123
	fmt.Println(&str, strPtr, &strPtr) // 0xc000026070 0xc000026070 0xc000088020
}

// new、make
func function16() {
	a := new(bool)
	fmt.Printf("%T %t %v\n", a, *a, a) // *bool false 0xc000192068

	b := make([]int, 1, 2)
	fmt.Printf("%T %v %p %p %p\n", b, b, b, &b, &b[0]) // []int [0] 0xc0001920b0 0xc000190030 0xc0001920b0
}

func main() {
}
